package com.zf.developaccumulate.utils;

import com.zf.developaccumulate.entity.StartEndDateVO;
import org.apache.commons.collections4.CollectionUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * 多条开始、结束时间数据，将有交叉的分到一组里。
 * 前提：每条记录中的 开始时间 < 结束时间。
 */
public class CrossDateGroupUtils {

    public static void main(String[] args) {
        List<StartEndDateVO> mockDataList = getMockDataList();
        List<List<StartEndDateVO>> res = groupByCrossDate(mockDataList);
        System.out.println(res);
    }


    /**
     * 将开始、结束时间存在交叉的数据分到一组中
     */
    public static List<List<StartEndDateVO>> groupByCrossDate(List<StartEndDateVO> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            return Collections.emptyList();
        }

        // 存放分组结果
        List<List<StartEndDateVO>> allGroupList = new ArrayList<>();

        // 按照开始时间升序排序后，只需要一次遍历就可完成交叉判断分组
        dataList.sort(Comparator.comparing(StartEndDateVO::getStartDate));

        // 每一组
        ArrayList<StartEndDateVO> curGroupList = new ArrayList<>();
        // 遍历分组
        for (StartEndDateVO curOne : dataList) {
            // 如果当前分组里面没有值，则直接放入分组中
            if (curGroupList.isEmpty()) {
                curGroupList.add(curOne);
                continue;
            }

            StartEndDateVO previousOne = curGroupList.get(curGroupList.size() - 1);
            // 如果当前值的开始时间 <= 前一个值的结束时间，则认为交叉，放入分组中
            if (!curOne.getStartDate().isAfter(previousOne.getEndDate())) {
                // 将结束时间最大的放在分组中的最后一个位置。
                // 如果当前的结束时间 <= 前一个的结束时间，那么直接将当前值放在组内最后一个会造成结束时间的范围变小，所以前一个值依然作为组内最后一个元素，当前值往前放。
                if (curOne.getEndDate().isBefore(previousOne.getEndDate())) {
                    curGroupList.add(curGroupList.size() - 1, curOne);
                } else {
                    // 如果当前的结束时间 > 前一个的结束时间，则将当前值放到组内的最后一个位置上
                    curGroupList.add(curOne);
                }
                continue;
            }

            // 没有交叉，则本次分组完成
            allGroupList.add(new ArrayList<>(curGroupList));
            // 清理分组，为下一次判断做准备
            curGroupList.clear();
            // 将当前值放入新分组中
            curGroupList.add(curOne);
        }
        // 放入最后一个分组，如果不空
        if (CollectionUtils.isNotEmpty(curGroupList)) {
            allGroupList.add(curGroupList);
        }

        // 对最终的分组数据排序，方便观察，无其他作用，可有可无
        for (List<StartEndDateVO> gp : allGroupList) {
            gp.sort(Comparator.comparing(StartEndDateVO::getStartDate));
        }

        return allGroupList;
    }


    /**
     * 假数据
     */
    private static List<StartEndDateVO> getMockDataList() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        List<StartEndDateVO> list = new ArrayList<>();

        list.add(new StartEndDateVO(LocalDate.parse("2024-06-07", formatter), LocalDate.parse("2024-06-09", formatter), 10));
        list.add(new StartEndDateVO(LocalDate.parse("2024-06-09", formatter), LocalDate.parse("2024-06-17", formatter), 20));
        list.add(new StartEndDateVO(LocalDate.parse("2024-06-11", formatter), LocalDate.parse("2024-06-22", formatter), 30));
        list.add(new StartEndDateVO(LocalDate.parse("2024-05-01", formatter), LocalDate.parse("2024-05-08", formatter), 40));
        list.add(new StartEndDateVO(LocalDate.parse("2024-03-07", formatter), LocalDate.parse("2024-03-18", formatter), 50));
        list.add(new StartEndDateVO(LocalDate.parse("2024-03-13", formatter), LocalDate.parse("2024-03-21", formatter), 60));
        list.add(new StartEndDateVO(LocalDate.parse("2024-10-01", formatter), LocalDate.parse("2024-10-12", formatter), 70));
        list.add(new StartEndDateVO(LocalDate.parse("2024-10-08", formatter), LocalDate.parse("2024-11-02", formatter), 80));
        list.add(new StartEndDateVO(LocalDate.parse("2024-11-08", formatter), LocalDate.parse("2024-11-14", formatter), 90));
        list.add(new StartEndDateVO(LocalDate.parse("2024-03-17", formatter), LocalDate.parse("2024-04-01", formatter), 90));

        // list.add(new StartEndDateVO(LocalDate.parse("2024-01-01", formatter), LocalDate.parse("2025-01-01", formatter), 90));

        return list;
    }
}
